﻿using System.ComponentModel;
using System.Xml.Serialization;
using T4UtilityBelt.Serializers;

namespace T4UtilityBelt.DataDesigns
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Property")]
    public abstract class Property : IXShouldSerialize
    {
        private string _secondaryType;
        private string _secondaryDefaultString;

        protected Property()
        {
            ShouldSerialize = true;
        }

        protected Property(string propertyType) : this()
        {
            PropertyType = propertyType;
        }

        protected Property(string propertyType, string name)
            : this(propertyType)
        {
            Name = name;
        }

        protected Property(string propertyType, string name, string secondaryType)
            : this(propertyType)
        {
            Name = name;
            SecondaryType = secondaryType;
        }

        protected Property(string propertyType, string name, bool required)
            : this(propertyType, name)
        {
            Required = required;
        }

        protected Property(string propertyType, string name, bool required, string secondaryType)
            : this(propertyType, name, secondaryType)
        {
            Required = required;
        }

        [XIgnore]
        public bool ShouldSerialize { get; set; }

        public string Name { get; set; }

        [XSpecifiedValue("IsPropertyTypeSpecified")]
        public string PropertyType { get; set; }

        [XIgnoreAttribute]
        public virtual bool IsPropertyTypeSpecified
        {
            get
            {
                return true;
            }
        }

        [XIgnore]
        private PropertyTypeInfo PropertyTypeInfo
        {
            get
            {
                if (PropertyTypeInfoProvider.PropertyTypes.ContainsKey(PropertyType))
                {
                    return PropertyTypeInfoProvider.PropertyTypes[PropertyType];
                }
                return null;
            }
        }

        [XSpecifiedValue("IsSecondaryTypeSpecified")]
        public string SecondaryType
        {
            get
            {
                if (_secondaryType == null)
                {
                    return PropertyType;
                }
                return _secondaryType;
            }
            set { _secondaryType = value; }
        }

        [XIgnoreAttribute]
        public virtual bool IsSecondaryTypeSpecified
        {
            get
            {
                return SecondaryType != PropertyType;
            }
        }

        [DefaultValue(false)]
        [XSpecifiedValue("IsRequiredSpecified")]
        public bool Required { get; set; }

        [XIgnore]
        public virtual bool IsRequiredSpecified
        {
            get { return true; }
        }

        //[XmlAttribute]
        //public int MaxDecimals { get; set; }

        [DefaultValue(false)]
        public bool NotSearchable { get; set; }

        [XIgnore]
        public Entity Entity { get; set; }

        [DefaultValue(false)]
        [XSpecifiedValue("IsReadOnlySpecified")]
        public bool ReadOnly { get; set; }

        [XIgnore]
        public virtual bool IsReadOnlySpecified
        {
            get { return true; }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public virtual string GetSqlType()
        {
            PropertyTypeInfo type = PropertyTypeInfo;
            if (type != null)
            {
                return type.SqlType;
            }
            return "";
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public virtual string GetTestData()
        {
            PropertyTypeInfo type = PropertyTypeInfo;
            if (type != null)
            {
                return type.CsTestData;
            }
            return "";
        }

        public string DefaultString { get; set; }

        public string SecondaryDefaultString
        {
            get
            {
                if (_secondaryDefaultString == null)
                {
                    return DefaultString;
                }
                return _secondaryDefaultString;
            }
            set { _secondaryDefaultString = value; }
        }

        //if (PropertyType == ":Decimal"
        //    || PropertyType == ":Decimal?")
        //{
        //    if (MaxLength == 0)
        //        return "DECIMAL";
        //    else
        //        return string.Format("DECIMAL({0},{1})", MaxLength, MaxDecimals);
        //}

        //public abstract string GetTestDataSql();

        //public abstract string GetTestDataXml();

        //public abstract string GetTestDataCs();

        internal virtual void FixModel(EntityModel model, Entity entity)
        {
            Entity = entity;
        }

        public virtual string RenderAssignFromServiceToModelCs(string toControl, string fromControl)
        {
            return string.Format("{1}.{0} = {2}.{0};", Name, toControl, fromControl);
        }

        public virtual string RenderAssignFromModelToServiceCs(string toControl, string fromControl)
        {
            return string.Format("{1}.{0} = {2}.{0};", Name, toControl, fromControl);
        }

        public virtual string RenderInterfaceModelCs()
        {
            return string.Format("{1} {0} {{ get; set; }}", Name, PropertyType);
        }

        public virtual string RenderInterfaceServiceCs()
        {
            return string.Format("{1} {0} {{ get; set; }}", Name, PropertyType);
        }

        public virtual string RenderModelCs()
        {
            return string.Format(@"
        public {1} {0}
        {{
            get
            {{
                return this._{0};
            }}
            set
            {{
                if ({0} != value)
                {{
                    this.On{0}Changing(value);
                    this._{0} = value;
                    this.On{0}Changed();
                    this.OnPropertyChanged(""{0}"");
                }}
            }}
        }}

        private {1} _{0};
        partial void On{0}Changing({1} value);
        partial void On{0}Changed();
", Name, PropertyType);
        }

        public abstract UxDesigns.Control CreateControl();
    }
}